#ifndef __QTCH_MUTEX_H__
#define __QTCH_MUTEX_H__


#include<pthread.h>
#include<semaphore.h>
#include<iostream>

#include"noncopyable.h"

namespace qtch{

class Semaphore :Noncopyable{
public:
    Semaphore();
    ~Semaphore();
    void wait();
    void notify();
private:
    sem_t m_sem;
};


template<class T>
class ScopedLockImp{
public:
    ScopedLockImp(T& mutex)
    :m_mutex(mutex){
        lock();
    }
    ~ScopedLockImp(){
        unlock();
    }
    
    void lock(){
        if(!m_locked){
            m_mutex.lock();
            m_locked = true;
        }
    }
    
    void unlock(){
        if(m_locked){
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T& m_mutex;
    bool m_locked = false;
};

template<class T>
class ReadScopedLockImp : Noncopyable{
public:

    ReadScopedLockImp(T& mutex)
    :m_mutex(mutex){
        lock();
    }
    ~ReadScopedLockImp(){
        unlock();
    }
    
    void lock(){
        if(!m_locked){
            m_mutex.rlock();
            m_locked = true;
        }
    }
    
    void unlock(){
        if(m_locked){
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T & m_mutex;
    bool m_locked = false;
};

template<class T>
class WritescopedLockImp : Noncopyable{
public:

    WritescopedLockImp(T& mutex)
    :m_mutex(mutex){
        lock();
    }
    ~WritescopedLockImp(){
        unlock();
    }
    
    void lock(){
        if(!m_locked){
            m_mutex.wlock();
            m_locked = true;
        }
    }
    
    void unlock(){
        if(m_locked){
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T & m_mutex;
    bool m_locked = false;
};

class Mutex : Noncopyable{
public:
    typedef ScopedLockImp<Mutex> Lock;
    Mutex(){
        pthread_mutex_init(&m_mutex,NULL);
    }

    ~Mutex(){
        pthread_mutex_destroy(&m_mutex);
    }

    void lock(){
        pthread_mutex_lock(&m_mutex);
    }

    void unlock(){
        pthread_mutex_unlock(&m_mutex);
    }


private:
pthread_mutex_t m_mutex;
};



class RWMutex : Noncopyable{
public:
    typedef ReadScopedLockImp<RWMutex> ReadLock;
    typedef WritescopedLockImp<RWMutex> WriteLock;
    RWMutex();
    ~RWMutex();
    void rlock();
    void wlock();
    void unlock();

private:
    pthread_rwlock_t m_lock;
};

class NullMutex: Noncopyable{
public:
    typedef ScopedLockImp<NullMutex> Lock;
    NullMutex(){
        
    }

    ~NullMutex(){
        
    }

    void lock();

    void unlock();
};


}



#endif